package com.ruoyi.learn.java.design.pattern.struct;

/**
 * 桥接模式 (Bridge Pattern) 示例：分离形状的抽象与渲染的实现。
 */
public class BridgePatternDemo {

    //region ========== 1. 实现者 (Implementor) - 渲染平台 ==========

    /**
     * 实现者接口：渲染器
     * 定义了在不同平台上绘制图形的基本操作。
     * 抽象部分（形状）将通过此接口与具体实现交互。
     */
    public interface Renderer {
        void renderCircle(double x, double y, double radius);
        void renderSquare(double x, double y, double side);
        // 可以添加更多绘制方法
    }

    /**
     * 具体实现者：Windows 渲染器
     * 实现了在 Windows 平台上的具体绘制逻辑。
     */
    public static class WindowsRenderer implements Renderer {
        @Override
        public void renderCircle(double x, double y, double radius) {
            System.out.println("      > [Windows] 使用 GDI+ 绘制圆形：中心(" + x + ", " + y + "), 半径=" + radius);
        }

        @Override
        public void renderSquare(double x, double y, double side) {
            System.out.println("      > [Windows] 使用 GDI+ 绘制正方形：左上角(" + x + ", " + y + "), 边长=" + side);
        }
    }

    /**
     * 具体实现者：Linux 渲染器
     * 实现了在 Linux 平台上的具体绘制逻辑。
     */
    public static class LinuxRenderer implements Renderer {
        @Override
        public void renderCircle(double x, double y, double radius) {
            System.out.println("      > [Linux] 使用 X11/GL 绘制圆形：中心(" + x + ", " + y + "), 半径=" + radius);
        }

        @Override
        public void renderSquare(double x, double y, double side) {
            System.out.println("      > [Linux] 使用 X11/GL 绘制正方形：左上角(" + x + ", " + y + "), 边长=" + side);
        }
    }

    // 可以轻松添加新的平台，如 MacRenderer, WebRenderer 等

    //endregion

    //region ========== 2. 抽象 (Abstraction) - 图形 ==========

    /**
     * 抽象：图形
     * 包含一个对 Renderer 接口的引用，将具体的渲染工作委托给实现者。
     * 定义了所有图形的通用接口。
     */
    public static abstract class Shape {
        protected Renderer renderer; // <<<< 核心：组合而非继承

        // 构造函数注入实现
        public Shape(Renderer renderer) {
            this.renderer = renderer;
        }

        // 抽象方法，由子类实现具体逻辑
        public abstract void draw();
        public abstract void resizeByPercentage(double pct);
    }

    //endregion

    //region ========== 3. 精化抽象 (Refined Abstraction) ==========

    /**
     * 精化抽象：圆形
     * 扩展了抽象接口，实现了圆形特有的逻辑。
     */
    public static class Circle extends Shape {
        private double x, y; // 中心坐标
        private double radius;

        public Circle(double x, double y, double radius, Renderer renderer) {
            super(renderer); // 将 renderer 传递给父类
            this.x = x;
            this.y = y;
            this.radius = radius;
        }

        @Override
        public void draw() {
            System.out.println("  > 【圆形】正在绘制...");
            // 将具体的绘制工作委托给 renderer
            renderer.renderCircle(x, y, radius);
        }

        @Override
        public void resizeByPercentage(double pct) {
            radius *= (1 + pct / 100);
            System.out.println("  > 【圆形】大小已调整 " + pct + "%，新半径=" + radius);
        }

        // 圆形特有的方法
        public double getArea() {
            return Math.PI * radius * radius;
        }
    }

    /**
     * 精化抽象：正方形
     * 扩展了抽象接口，实现了正方形特有的逻辑。
     */
    public static class Square extends Shape {
        private double x, y; // 左上角坐标
        private double side;

        public Square(double x, double y, double side, Renderer renderer) {
            super(renderer);
            this.x = x;
            this.y = y;
            this.side = side;
        }

        @Override
        public void draw() {
            System.out.println("  > 【正方形】正在绘制...");
            // 将具体的绘制工作委托给 renderer
            renderer.renderSquare(x, y, side);
        }

        @Override
        public void resizeByPercentage(double pct) {
            side *= (1 + pct / 100);
            System.out.println("  > 【正方形】大小已调整 " + pct + "%，新边长=" + side);
        }

        // 正方形特有的方法
        public double getArea() {
            return side * side;
        }
    }

    // 可以轻松添加新的形状，如 Triangle, Rectangle 等

    //endregion

    //region ========== 4. 客户端 (Client) ==========

    /**
     * 图形应用客户端
     * 只需要知道 Shape 抽象和 Renderer 实现，可以自由组合。
     */
    public static class DrawingApp {
        public void drawShape(Shape shape) {
            System.out.println("【客户端】收到绘制图形请求：");
            shape.draw();
            System.out.println("【客户端】图形绘制完成。\n");
        }

        public void resizeAndDraw(Shape shape, double percentage) {
            System.out.println("【客户端】调整图形大小并绘制：");
            shape.resizeByPercentage(percentage);
            shape.draw(); // 重新绘制
            System.out.println("【客户端】调整并绘制完成。\n");
        }
    }

    //endregion

    //region ========== 5. 主函数 (Main) - 演示桥接模式 ==========

    public static void main(String[] args) {
        System.out.println("=== 桥接模式演示 ===\n");

        // 1. 创建不同平台的渲染器 (ConcreteImplementors)
        System.out.println("1. 创建渲染器...");
        Renderer windowsRenderer = new WindowsRenderer();
        Renderer linuxRenderer = new LinuxRenderer();

        // 2. 创建不同形状的图形 (Refined Abstractions)，并注入不同的渲染器
        System.out.println("2. 创建图形对象...\n");

        // === 组合 1: Windows 上的圆形 ===
        System.out.println("组合 1: Windows 平台上的圆形");
        Shape circleOnWindows = new Circle(10, 10, 5, windowsRenderer); // <<<< 桥接：组合
        DrawingApp app1 = new DrawingApp();
        app1.drawShape(circleOnWindows);

        // === 组合 2: Linux 上的圆形 ===
        System.out.println("组合 2: Linux 平台上的圆形");
        Shape circleOnLinux = new Circle(20, 20, 8, linuxRenderer); // <<<< 桥接：组合
        DrawingApp app2 = new DrawingApp();
        app2.drawShape(circleOnLinux);

        // === 组合 3: Windows 上的正方形 ===
        System.out.println("组合 3: Windows 平台上的正方形");
        Shape squareOnWindows = new Square(5, 5, 6, windowsRenderer); // <<<< 桥接：组合
        DrawingApp app3 = new DrawingApp();
        app3.drawShape(squareOnWindows);

        // === 组合 4: Linux 上的正方形 ===
        System.out.println("组合 4: Linux 平台上的正方形");
        Shape squareOnLinux = new Square(15, 15, 10, linuxRenderer); // <<<< 桥接：组合
        DrawingApp app4 = new DrawingApp();
        app4.drawShape(squareOnLinux);

        // 3. 演示运行时切换实现 (可选)
        System.out.println("3. 演示：运行时切换渲染器 (可选)...");
        // 注意：通常 Shape 的 renderer 在构造时确定，但我们可以设计 setter 来支持切换
        // 这里为了演示，假设我们有一个 setter (代码中未实现，仅概念)
        System.out.println("    > (概念) 可以让一个图形在 Windows 和 Linux 之间切换渲染方式。");

        // 4. 演示调整大小
        System.out.println("\n4. 演示：调整图形大小...");
        app1.resizeAndDraw(circleOnWindows, 20); // 将 Windows 上的圆放大 20%

        // 5. 对比：如果不使用桥接模式（类爆炸）
        System.out.println("--- 对比：不使用桥接模式 ---");
        System.out.println("如果使用继承，需要创建的类：");
        System.out.println("  - WindowsCircle, WindowsSquare");
        System.out.println("  - LinuxCircle, LinuxSquare");
        System.out.println("如果增加一个 Mac 平台，则需要再增加 MacCircle, MacSquare。");
        System.out.println("如果增加一个 Triangle 形状，则需要增加 WindowsTriangle, LinuxTriangle, MacTriangle...");
        System.out.println("类的数量 = 形状数量 * 平台数量，容易导致类爆炸。");
        System.out.println("而使用桥接模式，只需增加一个 Triangle 类和一个 MacRenderer 类即可。");
    }

    //endregion
}
